#include "FinalProject.h"
#include "EntityNames.h"


bool analyzed;
bool analysis_just_finished;
BWTA::Region* home;
using namespace BWAPI;


void FinalProject::onStart()
{
	int unitId = 1;
	updateAgents = false;

	BWTA::readMap();
	analyzed=false;
	analysis_just_finished=false;

#ifndef _DEBUG
	Broodwar->printf("Analyzing map... this may take a minute");
    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AnalyzeThread, NULL, 0, NULL);
#endif

	//*********************** Basic printout of map information *************
	//***********************************************************************
	Broodwar->printf("The map is %s, a %d player map",Broodwar->mapName().c_str(),Broodwar->getStartLocations().size());
	// Enable some cheat flags
	Broodwar->enableFlag(Flag::UserInput);
	//Broodwar->enableFlag(Flag::CompleteMapInformation);

	Broodwar->printf("The match up is %s v %s",
	Broodwar->self()->getRace().getName().c_str(),
	Broodwar->enemy()->getRace().getName().c_str());
	//***********************************************************************

	//*********************** Setup/Initialize the BT ***********************
	BT->Initialize();
	BT->DebugPrintTree();
	//***********************************************************************

	//START
	updateAgents = true;
	Broodwar->setLocalSpeed(1);
}


DWORD WINAPI AnalyzeThread()
{
  BWTA::analyze();

  //start location only available if the map has base locations
  if (BWTA::getStartLocation(BWAPI::Broodwar->self())!=NULL)
  {
    home       = BWTA::getStartLocation(BWAPI::Broodwar->self())->getRegion();
  }
  analyzed   = true;
  analysis_just_finished = true;
  return 0;
}


void FinalProject::onEnd(bool isWinner)
{
  if (isWinner)
  {
    //log win to file
  }
}

void FinalProject::onFrame()
{
	if (Broodwar->isReplay())
	return;

	drawStats();

	if (updateAgents)
	{
		if(Broodwar->getFrameCount()%5 == 0)
		{
			BT->Update();
			BT->DebugPrintTree();
		}
		if(BB->GetThreatMap())
		{
			//BB->GetThreatMap()->Refresh();
			//BB->GetThreatMap()->DebugDraw();
		}

		std::list<MarineSM*>::iterator marineBegin = BB->GetMarineSMs()->begin(), marineEnd = BB->GetMarineSMs()->end();
		std::vector<MarineSM*> deleteList;
		while(marineBegin != marineEnd)
		{
			MarineSM* marine = *marineBegin;
			if(marine->expired())
			{
				deleteList.push_back(marine);
			}
			else
			{
				marine->onFrame();
			}
			marineBegin++;
		}
		for(int i=0;i<deleteList.size();i++) {
			MarineSM* m = deleteList[i];
			// somehow remove it from BB's list
		}
	}
	if(analysis_just_finished)
	{
		Broodwar->printf("Terrain analysis has finished.\n");
		analysis_just_finished = false;
	}
}

void FinalProject::onSendText(std::string text)
{
  if (text=="/start")
  {
	  updateAgents = true;
  }
  else if (text == "/stop")
  {
		updateAgents = false;
  }
  else
  {
    Broodwar->printf("You typed '%s'!",text.c_str());
    Broodwar->sendText("%s",text.c_str());
  }
}

void FinalProject::onReceiveText(BWAPI::Player* player, std::string text)
{
  //Broodwar->printf("%s said '%s'", player->getName().c_str(), text.c_str());
}

void FinalProject::onPlayerLeft(BWAPI::Player* player)
{
  //Broodwar->sendText("%s left the game.",player->getName().c_str());
}

void FinalProject::onNukeDetect(BWAPI::Position target)
{
 /* if (target!=Positions::Unknown)
    Broodwar->printf("Nuclear Launch Detected at (%d,%d)",target.x(),target.y());
  else
    Broodwar->printf("Nuclear Launch Detected");*/
}

void FinalProject::onUnitDiscover(BWAPI::Unit* unit)
{
 // if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
   // Broodwar->sendText("A %s [%x] has been discovered at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
  if(unit->getPlayer()->isEnemy(Broodwar->self()))
  {
	  BB->AddEnemyUnit(unit); 
  }
}

void FinalProject::onUnitEvade(BWAPI::Unit* unit)
{
 // if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
   // Broodwar->sendText("A %s [%x] was last accessible at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
}

void FinalProject::onUnitShow(BWAPI::Unit* unit)
{
 // if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
   // Broodwar->sendText("A %s [%x] has been spotted at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
  
}

void FinalProject::onUnitHide(BWAPI::Unit* unit)
{
 // if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
   // Broodwar->sendText("A %s [%x] was last seen at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
	if(unit->getType() == UnitTypes::Zerg_Lurker)
		BB->SetCloakedEnemyPosition(unit->getPosition());
}

void FinalProject::onUnitCreate(BWAPI::Unit* unit)
{
  if (Broodwar->getFrameCount()>1)
  {
    if (!Broodwar->isReplay())
	{
		//Broodwar->sendText("A %s [%x] has been created at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
		BB->AddUnit(unit);
	}
    else
    {
      /*if we are in a replay, then we will print out the build order
      (just of the buildings, not the units).*/
      if (unit->getType().isBuilding() && unit->getPlayer()->isNeutral()==false)
      {
        int seconds=Broodwar->getFrameCount()/24;
        int minutes=seconds/60;
        seconds%=60;
       // Broodwar->sendText("%.2d:%.2d: %s creates a %s",minutes,seconds,unit->getPlayer()->getName().c_str(),unit->getType().getName().c_str());
      }
    }
  }
}

void FinalProject::onUnitDestroy(BWAPI::Unit* unit)
{
	if(Broodwar->self() == unit->getPlayer())
	{
		BB->RemoveUnit(unit);
	}
	if(unit->getPlayer()->isEnemy(Broodwar->self()))
    {
		BB->RemoveEnemyUnit(unit); 
    }
	
	/*if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
		Broodwar->sendText("A %s [%x] has been destroyed at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());*/
}

void FinalProject::onUnitMorph(BWAPI::Unit* unit)
{
  if((unit->getType() == UnitTypes::Terran_Refinery))
	  BB->AddUnit(unit);
//if (!Broodwar->isReplay())
//    Broodwar->sendText("A %s [%x] has been morphed at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
  else
  {
    /*if we are in a replay, then we will print out the build order
    (just of the buildings, not the units).*/
    if (unit->getType().isBuilding() && unit->getPlayer()->isNeutral()==false)
    {
      int seconds=Broodwar->getFrameCount()/24;
      int minutes=seconds/60;
      seconds%=60;
     // Broodwar->sendText("%.2d:%.2d: %s morphs a %s",minutes,seconds,unit->getPlayer()->getName().c_str(),unit->getType().getName().c_str());
    }
  }
}

void FinalProject::onUnitRenegade(BWAPI::Unit* unit)
{
 /* if (!Broodwar->isReplay())
    Broodwar->sendText("A %s [%x] is now owned by %s",unit->getType().getName().c_str(),unit,unit->getPlayer()->getName().c_str());*/
}

void FinalProject::onSaveGame(std::string gameName)
{
  //Broodwar->printf("The game was saved to \"%s\".", gameName.c_str());
}

void FinalProject::drawStats()
{
	std::set<Unit*> myUnits = Broodwar->self()->getUnits();
	Broodwar->drawTextScreen(5,0,"I have %d units:",myUnits.size());
	std::map<UnitType, int> unitTypeCounts;
	for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
	{
		/* if ((*i)->getType() == UnitTypes::Terran_Science_Vessel)
		Broodwar->printf("Current position (%d,%d)\n",(*i)->getPosition().x(),(*i)->getPosition().y());*/
		if (unitTypeCounts.find((*i)->getType())==unitTypeCounts.end())
		{
			unitTypeCounts.insert(std::make_pair((*i)->getType(),0));
		}
		unitTypeCounts.find((*i)->getType())->second++;
	}
	int line=1;
	for(std::map<UnitType,int>::iterator i=unitTypeCounts.begin();i!=unitTypeCounts.end();i++)
	{
		Broodwar->drawTextScreen(5,16*line,"- %d %ss",(*i).second, (*i).first.getName().c_str());
		line++;
	}
	Broodwar->drawTextScreen(5,16*line,"Min Balance to Spend: %d, Gas Balance to Spend: %d",BB->mineralBalanceToSpend, BB->gasBalanceToSpend);
	++line;
	Broodwar->drawTextScreen(5,16*line,"Min Last Frame: %d, Gas Last Frame: %d",BB->mineralsLastFrame, BB->gasLastFrame);
	++line;
	Broodwar->drawTextScreen(5,16*line,"Supply Balance to Spend: %d, Supply Used: %d",BB->supplyBalanceToSpend, BB->realSupplyUsed);
}

